<script lang="ts" setup name="FsSearchSelect">
import { Option, OptionValue, SelectModelValue } from './type';
import { ref, useAttrs, computed, watch } from 'vue';

type Props = {
  modelValue?: SelectModelValue;
  // 搜索函数
  searchMethod: (key: string) => Promise<Option[]>;
  // 为空的时候是否搜索
  searchEmpty?: boolean;
  // 初始选项列表，用于回显时初始化
  initOptions?: Option[];
  // 是否显示值在右边
  showValue?: boolean;

  // 搜索延迟时间, 单位毫秒
  duration?: number;

  multiple?: boolean;
  showChoiceAll?: boolean
};

const props = withDefaults(defineProps<Props>(), {
  modelValue: '',
  searchMethod: () => Promise.resolve([]),
  duration: 300,
  searchEmpty: true,
  showChoiceAll: false
});

const emits = defineEmits(['update:modelValue', 'change']);

const options = ref<Option[]>(props.initOptions || []);

const selectOptoins = ref<Option[]>(props.initOptions || []);

const inValue = ref<SelectModelValue>(props.modelValue);

const loading = ref<boolean>(false);

const popVisible = ref<boolean>(false);

const queryValue = ref('')

const modelValueHandle = (value: SelectModelValue) => {
  inValue.value = value;
  emits('update:modelValue', value);
};

const changeHandle = (value: SelectModelValue) => {
  let selected;
  if (props.multiple) {
    let allValue = options.value.map(item => item.value);
    selected = options.value.filter(item => (value as OptionValue[]).indexOf(item.value) > -1);
    selectOptoins.value = [
      ...selectOptoins.value.filter(item => allValue.indexOf(item.value) === -1),
      ...selected,
    ];
    selected = selectOptoins.value;
  } else {
    selected = options.value.find(item => {
      return item.value == value;
    });
    selectOptoins.value = selected ? [selected] : [];
  }
  emits('change', { value, selected });
};

const emptyList = ref<any>([])

const visibleChangeHandle = (visible: boolean) => {
  popVisible.value = visible;
  if (visible && !queryValue.value) {
    remoteMethod(queryValue.value)
  }
};

const removehTagHandle = (value: SelectModelValue) => {
  let index = selectOptoins.value.findIndex(item => item.value == value);
  if (index > -1) {
    selectOptoins.value.splice(index, 1);
  }
};

const debounce = (fn: Function, delay: number) => {
  let timer: any = null;
  return (...args: any[]) => {
    if (timer) {
      clearTimeout(timer);
    }
    timer = setTimeout(() => {
      fn.apply(this, args);
    }, delay);
  };
};

const remoteMethod = debounce((query: string) => {
  queryValue.value = query
  if (!props.searchMethod) {
    return;
  }

  if (!query) {
    if (!props.searchEmpty) {
      options.value = [];
      return;
    } else if (emptyList.value.length > 0) {
      options.value = emptyList.value;
      return
    }
  }
  loading.value = true;
  props.searchMethod(query).then(data => {
      if (!query) {
        emptyList.value = data;
      }
      if(queryValue.value == query) {
        options.value = data;
        loading.value = false;
      }
    })
    .catch((err: any) => {
      console.log(err);
      loading.value = false;
    });
}, props.duration);
if (!props.initOptions && (!Array.isArray(props.modelValue) || props.modelValue.length == 0) ) {
  remoteMethod(props.modelValue.toString());
}
watch(
  () => props.modelValue,
  val => {
    inValue.value = val;
  },
);
const isAll = ref(false)
const choiceAll = () => {
  if (!isAll.value) {
    const tar = options.value.map(item => {
      return item.value
    })
    emits('update:modelValue', tar)
  } else {
    emits('update:modelValue', [])
  }
  isAll.value = !isAll.value
}
defineExpose({
  options: options,
})
</script>
<template>
  <el-select
    class="w-full"
    :model-value="inValue"
    filterable
    remote
    :remote-method="remoteMethod"
    :loading="loading"
    :multiple="multiple"
    :collapse-tags-tooltip="true"
    :reserve-keyword="true"
    v-bind="$attrs"
    @remove-tag="removehTagHandle"
    @visible-change="visibleChangeHandle"
    @update:modelValue="modelValueHandle"
    @change="changeHandle">
    <template v-if="showChoiceAll" #header>
      <el-button type="primary" size="small" @click="choiceAll">
        {{ !isAll ? '全选' : '取消' }}
      </el-button>
    </template>
    <el-option
      v-for="item in options"
      :key="item.value"
      :value="item.value"
      :label="item.label">
      <slot name="option" :item="item">
        <span style="float: left;">{{ item.label }}</span>
        <span v-if="showValue" style="float: right; color: #8492a6;">[{{ item.value }}]</span>
      </slot>
    </el-option>
  </el-select>
</template>
